package Jogo.Comm {
	import flash.geom.Point;
	import flash.sampler.NewObjectSample;
	
	public class Message {
		private var msg:String; //The message received/to be sent in the String format
		
		//Values of the 'header' field
		private var sender:String;
		private var receiver:String;
		private var bodySize:int;
		private var type:int;
		
		//Parameters of the 'data' field
		private var action:int; //COMM_MANAGEMENT: (des)connect. ENTITY_UPDATE: create/sell/upgrade. GAME_STATE: start/win/lose
		private var ip:String; //IP of the device that is (des)connecting. COMM_MANAGEMENT
		private var tileX:int; //The X tile of the entity being update. ENTITY_UPDATE
		private var tileY:int; //The Y tile of the entity being update. ENTITY_UPDATE
		private var turret:int; //The type of the turret that is going to be created. ENTITY_UPDATE
		
		private var pt : Vector.<Point>; //Used with the 'players' below, describes the ENTITY_REDEFINITION
		private var players : Vector.<int> ; //The number of the player the entity belongs to. ENTITY_REDEFINITION
		private var entityType : Vector.<int>; //The type of the entity. ENTITY_REDEFINITION
		private var entityLevel : Vector.<int>; //The level of the entity. ENTITY_REDEFINITION
		
		private var player : int; //The id of the player. ENTITY_REDEFINITON
		
		public function Message() {
			msg = new String();
		}
		
		public function decode(message:String):void{
			msg = message.toLowerCase();
			decodeHeader();
			
			switch (type){
				case MsgHandler.CONNECT:
					ip = findField(msg, "sender");
					
					break;
				case MsgHandler.DISCONNECT:
					ip = findField(msg, "sender");
					
					break;
				case MsgHandler.ENTITY_REDEFINITION:
					//This module doesn't receive Entity_Redefinition messages. Only sends it
					break;
				
				case MsgHandler.ENTITY_UPDATE:
					action = int(findField(msg, "action"));
					tileX = int(findField(msg, "tilex"));
					tileY = int(findField(msg, "tiley"));
					turret = int(findField(msg, "turret"));
					break;
				
				case MsgHandler.GAME_STATE:
					//This module doesn't receive Game_State messages. Only sends it
					break;
				case MsgHandler.ACK:
					break;
			}
		}
		
		
		private function decodeHeader():void{
			sender = findField(msg, "sender");
			receiver = findField(msg, "receiver");
			type = int(findField(msg, "type"));
			bodySize = int(findField(msg, "bodysize"));
		}
		
		private function createHeader(receiver:String, type:int, bodySize:int):void{
			msg = msg.concat( "{" +
				"	Receiver: "+receiver+",\n" +
				"	Sender: "+FlashSocket.getThisIp()+",\n" +
				"	Type: "+type.toString()+",\n" +
				"	BodySize: "+bodySize+",\n" +
				"	Body: {\n");
		}
		
		public function createEntityRedefinitionMessage(pla:Vector.<int>, pts:Vector.<Point>, entityType:Vector.<int>,
														entityLevel:Vector.<int>, playerNumber:int, receiver:String):void{
			var i :int;
			var aux:String = new String();
			
			aux = aux.concat(	"		PlayerNumber : "+playerNumber.toString()+",\n" +
				"		Entities: [\n");
			
			if(pla.length >= 0){
				aux = aux.concat(	"			{TileX: "+pts[0].x.toString()+", TileY: "+pts[0].y.toString()+", Player: "+pla[0].toString()+", Entity: "+entityType[0].toString()+", Level: "+entityLevel[0].toString()+"}");
				for(i=1; i<pla.length; i++){
					aux = aux.concat(	",\n" +
						"			{TileX: "+pts[i].x.toString()+", TileY: "+pts[i].y.toString()+", Player: "+pla[i].toString()+", Entity: "+entityType[i].toString()+", Level: "+entityLevel[i].toString()+"}");
				}
				aux = aux.concat(	"\n			]\n" +
					"		}\n" +
					"}");
			}
			
			createHeader(receiver, MsgHandler.ENTITY_REDEFINITION, aux.length);
			
			msg = msg.concat(aux);
			this.pt = pts;
			this.players = pla;
			this.entityType = entityType;
			this.entityLevel = entityLevel;
		}
		
		public function createEntityUpdateMessage(action: int, x:int, y:int, receiver:String, turret:int = 0):void{
			var aux:String = new String();
			
			aux = aux.concat(	"		Action: "+action.toString()+",\n" +
				"		TileX: "+x.toString()+",\n" +
				"		TileY: "+y.toString()+",\n" +
				"		Turret: "+turret.toString()+"\n" +
				"	}\n" +
				"}");
			
			createHeader(receiver, MsgHandler.ENTITY_UPDATE, aux.length);
			msg = msg.concat(aux);
		}
		
		public function createGameStateMessage(action:int, receiver:String):void{
			var aux:String = new String();
			
			aux = aux.concat(	"		Action: "+action.toString()+"\n" +
				"	}\n" +
				"}");
			
			createHeader(receiver, MsgHandler.GAME_STATE, aux.length);
			msg = msg.concat(aux);
		}
		
		public function createErrorMessage(errorMsg:String, receiver:String):void{
			var aux:String = new String();
			
			aux = aux.concat(	"		Error: "+errorMsg+"\n" +
				"	}\n" +
				"}");	
			
			createHeader(receiver, MsgHandler.ERROR, aux.length);
			msg = msg.concat(aux);
		}
		
		/** Search for 'field' in the string 'msg' and return the 
		 * paramater after the ':'.
		 * 
		 * @param msg The string with the message.
		 * @param field The field we are looking for.
		 * @return The value of that 'field'.
		 */
		private static function findField(msg:String, field:String) : String{
			var i : int = msg.search(field);
			
			//Puts the j index in the starting index of the name of the field
			for(var j : int = i+field.length; 
				((msg.charAt(j) == " ") || (msg.charAt(j) == ":")); j++)
			{}
			
			//Concat the agent name in the 'temp' String
			var temp : String = new String();
			for (;((msg.charAt(j) != " ") && (msg.charAt(j) != "\n") && (msg.charAt(j) != ',')); j++){
				temp = temp.concat(msg.charAt(j));
			}
			
			return temp;
		}
		
		//getters and setters
		public function getIP():String{
			return this.ip;
		}
		
		public function setPt(pt:Vector.<Point>):void{
			this.pt = pt;
		}
		public function setPlayers(players : Vector.<int>):void{
			this.players = players;
		}
		
		public function getType():int{
			return this.type;
		}
		public function getAction():int{
			return this.action;
		}
		
		public function getTurret():int{
			return this.turret;
		}
		public function getPoint():Point{
			return (new Point(tileX, tileY));
		}
		public function getMsg():String{
			return msg;
		}
		public function getSender():String{
			return this.sender;
		}
	}
}